package com.example.apitesttool.service;

import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import jakarta.annotation.PostConstruct;

import java.time.Duration;

/**
 * AI 聊天服务
 * <p>
 * 提供基于 LangChain4j 的对话式接口测试能力，支持多种大模型切换。
 * 集成了各种工具，使 AI 能够执行 HTTP 请求、管理文档和参数等操作。
 * <p>
 * 支持的模型：
 * - OpenAI GPT-4o, GPT-4, GPT-3.5-turbo
 * - DeepSeek Chat
 * - 其他兼容 OpenAI API 的模型
 * <p>
 * 特性：
 * - 多模型配置切换
 * - 集成 HTTP 请求工具
 * - 文档管理能力
 * - 参数管理能力
 * - 上下文感知的测试建议
 *
 * @author liuxy
 * @version 1.0.0
 */
@Service
public class AiChatService {

    private static final Logger logger = LoggerFactory.getLogger(AiChatService.class);

    // 模型配置
    @Value("${ai.model.provider:openai}")
    private String modelProvider;

    @Value("${ai.model.name:gpt-4o}")
    private String modelName;

    @Value("${ai.model.temperature:0.1}")
    private double temperature;

    @Value("${ai.model.timeout:60}")
    private int timeoutSeconds;

    @Value("${ai.model.max-retries:3}")
    private int maxRetries;

    // OpenAI 配置
    @Value("${openai.api.key:}")
    private String openaiApiKey;

    @Value("${openai.api.base.url:https://api.openai.com/v1}")
    private String openaiBaseUrl;

    // DeepSeek 配置
    @Value("${deepseek.api.key:}")
    private String deepseekApiKey;

    @Value("${deepseek.api.base.url:https://api.deepseek.com/v1}")
    private String deepseekBaseUrl;

    // 自定义模型配置
    @Value("${custom.api.key:}")
    private String customApiKey;

    @Value("${custom.api.base.url:}")
    private String customBaseUrl;

    private final HttpRequestTools httpRequestTools;
    private final DocumentManagementTools documentManagementTools;

    @Autowired
    private ParameterManagementTools parameterManagementTools;

    @Autowired
    private RagQueryTools ragQueryTools;

    private TestAgent testAgent;
    private String currentModelInfo;

    @Autowired
    public AiChatService(HttpRequestTools httpRequestTools,
                         DocumentManagementTools documentManagementTools) {
        this.httpRequestTools = httpRequestTools;
        this.documentManagementTools = documentManagementTools;
    }

    @PostConstruct
    public void initializeAiService() {
        try {
            logger.info("正在初始化 AI 聊天服务，模型提供商: {}, 模型: {}", modelProvider, modelName);

            ChatLanguageModel chatModel = createChatModel();

            // 创建 AI 服务，集成所有工具
            testAgent = AiServices.builder(TestAgent.class)
                    .chatLanguageModel(chatModel)
                    .chatMemory(MessageWindowChatMemory.withMaxMessages(100))
                    .tools(httpRequestTools, documentManagementTools, parameterManagementTools, ragQueryTools)
                    .build();

            currentModelInfo = String.format("%s - %s", modelProvider, modelName);
            logger.info("AI 聊天服务初始化成功，当前模型: {}", currentModelInfo);

        } catch (Exception e) {
            logger.error("初始化 AI 聊天服务失败", e);
            throw new RuntimeException("AI 聊天服务初始化失败: " + e.getMessage(), e);
        }
    }

    /**
     * 根据配置创建聊天模型
     *
     * @return 配置好的聊天模型
     */
    private ChatLanguageModel createChatModel() {
        switch (modelProvider.toLowerCase()) {
            case "openai":
                return createOpenAiModel();
            case "deepseek":
                return createDeepSeekModel();
            case "custom":
                return createCustomModel();
            default:
                logger.warn("未知的模型提供商: {}，使用默认的 OpenAI", modelProvider);
                return createOpenAiModel();
        }
    }

    /**
     * 创建 OpenAI 模型
     */
    private ChatLanguageModel createOpenAiModel() {
        String apiKey = getApiKey(openaiApiKey, "OPENAI_API_KEY");

        if (apiKey == null || apiKey.trim().isEmpty()) {
            throw new IllegalStateException("OpenAI API Key 未配置。请设置环境变量 OPENAI_API_KEY 或在配置文件中设置 openai.api.key");
        }

        logger.info("创建 OpenAI 模型: {}", modelName);

        return OpenAiChatModel.builder()
                .apiKey(apiKey)
                .baseUrl(openaiBaseUrl)
                .modelName(modelName)
                .temperature(temperature)
                .timeout(Duration.ofSeconds(timeoutSeconds))
                .maxRetries(maxRetries)
                .build();
    }

    /**
     * 创建 DeepSeek 模型
     */
    private ChatLanguageModel createDeepSeekModel() {
        String apiKey = getApiKey(deepseekApiKey, "DEEPSEEK_API_KEY");

        if (apiKey == null || apiKey.trim().isEmpty()) {
            throw new IllegalStateException("DeepSeek API Key 未配置。请设置环境变量 DEEPSEEK_API_KEY 或在配置文件中设置 deepseek.api.key");
        }

        logger.info("创建 DeepSeek 模型: {}", modelName);

        // DeepSeek 使用兼容 OpenAI 的 API
        return OpenAiChatModel.builder()
                .apiKey(apiKey)
                .baseUrl(deepseekBaseUrl)
                .modelName(modelName.isEmpty() ? "deepseek-chat" : modelName)
                .temperature(temperature)
                .timeout(Duration.ofSeconds(timeoutSeconds))
                .maxRetries(maxRetries)
                .build();
    }

    /**
     * 创建自定义模型
     */
    private ChatLanguageModel createCustomModel() {
        String apiKey = getApiKey(customApiKey, "CUSTOM_API_KEY");

        if (apiKey == null || apiKey.trim().isEmpty()) {
            throw new IllegalStateException("自定义模型 API Key 未配置。请设置环境变量 CUSTOM_API_KEY 或在配置文件中设置 custom.api.key");
        }

        if (customBaseUrl == null || customBaseUrl.trim().isEmpty()) {
            throw new IllegalStateException("自定义模型 Base URL 未配置。请在配置文件中设置 custom.api.base.url");
        }

        logger.info("创建自定义模型: {} (Base URL: {})", modelName, customBaseUrl);

        return OpenAiChatModel.builder()
                .apiKey(apiKey)
                .baseUrl(customBaseUrl)
                .modelName(modelName)
                .temperature(temperature)
                .timeout(Duration.ofSeconds(timeoutSeconds))
                .maxRetries(maxRetries)
                .build();
    }

    /**
     * 获取 API Key，优先从环境变量获取
     */
    private String getApiKey(String configValue, String envVarName) {
        String envValue = System.getenv(envVarName);
        if (envValue != null && !envValue.trim().isEmpty()) {
            return envValue.trim();
        }
        return configValue;
    }

    /**
     * 处理用户消息并返回 AI 响应
     *
     * @param userMessage 用户输入的消息
     * @return AI 的响应
     */
    public String processUserMessage(String userMessage) {
        if (testAgent == null) {
            return "AI 服务尚未初始化，请稍后再试。";
        }

        if (userMessage == null || userMessage.trim().isEmpty()) {
            return "请输入有效的消息。";
        }

        String trimmedMessage = userMessage.trim();
        logger.info("处理用户消息: {}", trimmedMessage.substring(0, Math.min(trimmedMessage.length(), 100)));

        int maxRetries = 3;
        for (int attempt = 1; attempt <= maxRetries; attempt++) {
            try {
                String response = testAgent.chat(trimmedMessage);
                logger.debug("AI 响应长度: {} 字符", response.length());
                return response;
            } catch (Exception e) {
                logger.warn("第 {} 次尝试失败: {}", attempt, e.getMessage());
                if (attempt == maxRetries) {
                    logger.error("处理用户消息时发生错误（已达最大重试次数）", e);
                    return "处理消息时发生错误: " + e.getMessage() + "\n\n请检查网络连接和 API 配置，然后重试。";
                }

                // 小延迟再试（可选）
                try {
                    Thread.sleep(300);
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    return "请求中断，已停止处理。";
                }
            }
        }

        return "未知错误，未能成功处理请求。";
    }


    /**
     * 检查 AI 服务是否可用
     *
     * @return 如果服务可用返回 true
     */
    public boolean isServiceAvailable() {
        return testAgent != null;
    }

    /**
     * 获取服务状态信息
     *
     * @return 服务状态描述
     */
    public String getServiceStatus() {
        if (testAgent == null) {
            return "AI 服务未初始化";
        }

        return String.format("AI 服务运行正常 (模型: %s)", currentModelInfo);
    }

    /**
     * 获取当前模型信息
     *
     * @return 当前使用的模型信息
     */
    public String getCurrentModelInfo() {
        return currentModelInfo != null ? currentModelInfo : "未知模型";
    }

    /**
     * 重新初始化服务（用于动态切换模型）
     */
    public void reinitializeService() {
        logger.info("重新初始化 AI 服务");
        initializeAiService();
    }

    /**
     * TestAgent 接口定义
     * <p>
     * 定义了 AI Agent 的系统消息和聊天方法。
     */
    public interface TestAgent {

        @SystemMessage("""
                你是一个专业的 API 接口测试助手，专门帮助用户进行自动化接口测试。你的主要职责包括：
                
                1. **文档管理**：
                   - 帮助用户查看已上传的 OpenAPI/Swagger 文档
                   - 切换和管理不同的文档
                   - 解释文档中的接口信息
                
                2. **参数管理**：
                   - 设置和管理固定参数（如 API Key、Authorization Token）
                   - 这些参数会自动添加到所有 HTTP 请求中
                
                3. **接口测试**：
                   - 根据用户需求执行 HTTP 请求（GET、POST、PUT、DELETE、PATCH）
                   - 分析响应结果并提供测试建议
                   - 设计测试用例和测试流程
                
                4. **智能建议**：
                   - 根据 OpenAPI 文档推荐测试场景
                   - 提供最佳实践建议
                   - 帮助用户理解接口的使用方法
                
                **重要规则**：
                - 始终使用中文与用户交流
                - 在执行 HTTP 请求前，确保用户已设置必要的固定参数
                - 如果用户提到"卸载文档"或类似表达，使用 removeDocument 工具删除指定文档
                - 提供清晰、详细的测试结果分析
                - 主动询问用户是否需要设置认证信息或其他必要参数
                - 当用户询问如何测试某个接口时，先查看当前活跃文档，然后提供具体的测试建议
                
                请以友好、专业的方式帮助用户完成接口测试任务。
                """)
        String chat(@UserMessage String userMessage);
    }
}

